package com.zero.base;


import com.zero.PublicResult;
import com.zero.ResultEnums;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.Predicate;
import java.util.*;

/**
 * 业务基类
 */
@NoArgsConstructor
public abstract class BaseService<E extends BaseEntity, ID, M extends BaseDao<E, ID>, Q extends BaseQuery> implements IBase<E, ID, Q> {
    @Autowired
    protected M mapper;
    protected JPAQueryFactory jpa;

    @Override
    @Transactional
    public PublicResult add(E e) {
        return PublicResult.resultEnums(ResultEnums.ADD_OK, mapper.save(e));
    }

    @Override
    @Transactional
    public PublicResult update(E e) {
        return PublicResult.resultEnums(ResultEnums.UPDATE_OK, mapper.save(e));
    }

    @Override
    public PublicResult get(ID id) {
        return PublicResult.resultEnums(ResultEnums.QUERY_OK, mapper.findById(id));
    }

    @Override
    public PublicResult list(Q q) {
        return PublicResult.resultEnums(ResultEnums.QUERY_OK, mapper.findAll(q.predicate(), q.getSort()));
    }

    @Override
    public PublicResult pageList(Q q) {
        int page = q.getPage();
        int pageSize = q.getPageSize();
        Page<E> all = mapper.findAll(q.predicate(), q.getPageable());
        PublicResult.PageResult build = PublicResult.PageResult.builder().page(page).pageSize(pageSize).total(all.getTotalElements()).data(all.getContent()).build();
        return PublicResult.resultEnums(ResultEnums.QUERY_OK, build);
    }

    @Override
    @Transactional
    public PublicResult deleteByIds(Collection<ID> ids) {
        ids.forEach(id -> {
            if (StringUtils.isNotBlank(id.toString())) {
                Optional<E> byId = mapper.findById(id);
                if (byId.isPresent()) {
                    mapper.deleteById(id);
                }
            }
        });
        return PublicResult.resultEnums(ResultEnums.DEL_OK);
    }

    @Override
    public boolean isExistData(Map<String, Object> map, List<String> keyList) {
        Specification<E> specification = (Specification<E>) (root, query, cb) -> {
            List<Predicate> predicateList = new ArrayList<>();
            map.forEach((key, value) -> {
                if (keyList.contains(key)) {
                    predicateList.add(cb.notEqual(root.get(key), value));
                } else {
                    predicateList.add(cb.equal(root.get(key), value));
                }
            });
            return cb.and(predicateList.toArray(new Predicate[0]));
        };
        return mapper.count(specification) > 0;
    }
}